package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.order.TrackPayVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

	@Autowired
	private VodConstantProperties vodConstantProperties;

	@Autowired
	private VodUploadClient client;

	@Autowired
	private AlbumInfoServiceImpl albumInfoService;

	@Autowired

	private TrackStatMapper trackStatMapper;

	@Autowired
	private  VodServiceImpl vodService;

	@Autowired
	private UserInfoFeignClient userInfoFeignClient;

	@Autowired
	private AlbumInfoMapper albumInfoMapper;

	@Autowired
	private AlbumStatMapper albumStatMapper;

	@Override
	public UploadTrackVo uploadTrack(MultipartFile file) {
		//  声音上传临时目录：
		String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file);


		//  构建上传请求对象
		VodUploadRequest request = new VodUploadRequest();

		//  设置视频本地地址
		request.setMediaFilePath(tempPath);

		//  指定任务流
		request.setProcedure(vodConstantProperties.getProcedure());

		try {
			//  调用上传方法
			VodUploadResponse response = client.upload(vodConstantProperties.getRegion(), request);

			// 获取结果
			String fileId = response.getFileId();
			String mediaUrl = response.getMediaUrl();

			// 封装响应结果
			UploadTrackVo uploadTrackVo = new UploadTrackVo();
			uploadTrackVo.setMediaFileId(fileId);
			uploadTrackVo.setMediaUrl(mediaUrl);

			return uploadTrackVo;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			new File(tempPath).delete();       // 删除临时文件
		}
	}

	@Override
	public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {

		// 创建声音对象
		TrackInfo trackInfo = new TrackInfo();
		BeanUtils.copyProperties(trackInfoVo, trackInfo);                // 属性拷贝
		trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
		trackInfo.setSource(SystemConstant.TRACK_SOURCE_UPLOAD);
		trackInfo.setUserId(userId);

		// 获取流媒体信息.
		TrackMediaInfoVo trackMediaInfo = vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());

		trackInfo.setMediaSize(trackMediaInfo.getSize());
		trackInfo.setMediaUrl(trackMediaInfo.getMediaUrl());
		trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfo.getDuration()));
		trackInfo.setMediaType(trackMediaInfo.getType());

		// 获取上一条声音
		TrackInfo preTrackInfo = this.getOne(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, trackInfoVo.getAlbumId()).orderByDesc(TrackInfo::getId).select(TrackInfo::getOrderNum).last("limit 1"));
		int orderNum = 1;
		if (null != preTrackInfo) {
			orderNum = preTrackInfo.getOrderNum() + 1;
		}
		trackInfo.setOrderNum(orderNum);
		this.save(trackInfo);

		//更新专辑声音总数
		AlbumInfo albumInfo = albumInfoService.getById(trackInfo.getAlbumId());
		int includeTrackCount = albumInfo.getIncludeTrackCount() + 1;
		albumInfo.setIncludeTrackCount(includeTrackCount);
		albumInfoService.updateById(albumInfo);

		// 初始化统计数据
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);

	}

	@Override
	public IPage<TrackListVo> findUserTrackPage(Long pageNo, Long pageSize, TrackInfoQuery trackInfoQuery) {

		// 获取当前登录用户的id
		Long userId = AuthContextHolder.getUserId();
		trackInfoQuery.setUserId(userId);

		// 创建Page对象，封装分页查询参数
		IPage<TrackListVo> page = new Page<>(pageNo , pageSize) ;
		trackInfoMapper.findUserTrackPage(page , trackInfoQuery) ;

		// 返回
		return page;
	}

	@Override
	public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {

		TrackInfo trackInfo = this.getById(id);
		String uploadMediaFileId = trackInfoVo.getMediaFileId(); // 获取提交过来的数据的声音id
		String dbMediaFileId = trackInfo.getMediaFileId();
		BeanUtils.copyProperties(trackInfoVo , trackInfo);

		//	获取声音信息.
		if (!uploadMediaFileId.equals(dbMediaFileId)) {

			//	说明已经修改过了.
			TrackMediaInfoVo trackMediaInfoVo = vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());
			if (null == trackMediaInfoVo){ //	判断对象不为空.
				throw new GuiguException(ResultCodeEnum.VOD_FILE_ID_ERROR);		//	抛出异常
			}
			trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
			trackInfo.setMediaType(trackMediaInfoVo.getType());
			trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
			trackInfo.setMediaSize(trackMediaInfoVo.getSize());
		}

		//	修改数据
		this.updateById(trackInfo);

	}

	@Override
	@Transactional
	public void removeTrackInfo(Long id) {

		// 获取声音对象数据
		TrackInfo trackInfo = this.getById(id);
		this.removeById(id);		// 删除

		//更新专辑声音总数
		AlbumInfo albumInfo = this.albumInfoService.getById(trackInfo.getAlbumId());
		int includeTrackCount = albumInfo.getIncludeTrackCount() - 1;
		albumInfo.setIncludeTrackCount(includeTrackCount);
		albumInfoService.updateById(albumInfo);

		//删除统计数据
		trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, id));

		//删除声音媒体
		vodService.removeTrack(trackInfo.getMediaFileId());
	}

	private void saveTrackStat(Long trackId, String trackType) {        // 保存统计数据
		TrackStat trackStat = new TrackStat();
		trackStat.setTrackId(trackId);
		trackStat.setStatType(trackType);
		trackStat.setStatNum(0);
		this.trackStatMapper.insert(trackStat);
	}

	@Override
	public IPage<AlbumTrackListVo> findAlbumTrackPage(Long albumId, Integer pageNo, Integer pageSize) {

		// 根据专辑的id查询专辑数据
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);

		// 创建一个Page对象
		IPage<AlbumTrackListVo> page = new Page<>(pageNo , pageSize) ;
		trackInfoMapper.findAlbumTrackPage(page , albumId) ;
		List<AlbumTrackListVo> records = page.getRecords();			// 获取当前页的声音列表数据

		/**
		 * 构建声音付费标记字段的值
		 */
		Long userId = AuthContextHolder.getUserId();
		if(userId == null) {		// 用户未登录

			// 判断专辑的付费类型
			String payType = albumInfo.getPayType();
			if(!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(payType)) {		// 非免费专辑
				Integer tracksForFree = albumInfo.getTracksForFree();       // 获取免费试听的声音的集数
				records.stream().filter(track -> track.getOrderNum() > tracksForFree).forEach(track -> track.setIsShowPaidMark(true));
			}

		}else {				// 用户已经登录了

			// 判断专辑的付费类型： 0101免费、0102vi免费、0103付费
			String payType = albumInfo.getPayType();
			if(SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {		// vip免费

				// 根据用户的id查找用户数据
				Result<UserInfo> userInfoResult = userInfoFeignClient.findByUserId(userId);
				UserInfo userInfo = userInfoResult.getData();
				Integer isVip = userInfo.getIsVip();
				if(isVip.equals(1)) {			// 是否vip用户

					// 判断vip是否过期了： 当当前系统时间 > vip过期时间
					long vipExpireTime = userInfo.getVipExpireTime().getTime();
					long currentTimeMillis = System.currentTimeMillis();
					if(currentTimeMillis > vipExpireTime) {
						Integer tracksForFree = albumInfo.getTracksForFree();       // 获取免费试听的声音的集数
						records.stream().filter(track -> track.getOrderNum() > tracksForFree).forEach(track -> track.setIsShowPaidMark(true));
					}

				}else {							// 不是vip用户
					Integer tracksForFree = albumInfo.getTracksForFree();       // 获取免费试听的声音的集数
					records.stream().filter(track -> track.getOrderNum() > tracksForFree).forEach(track -> track.setIsShowPaidMark(true));
				}

			}else if(SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)){   // 需要再次进行判断

				// 获取非试听的声音的id
				Integer tracksForFree = albumInfo.getTracksForFree();
				List<Long> trackIdList = records.stream().filter(track -> track.getOrderNum() > tracksForFree).map(track -> track.getTrackId()).collect(Collectors.toList());

				// 调用user微服务的接口查询用户是否购买过声音, 传递的参数是两个一个专辑的id、声音的id的list集合
				Result<Map<Long, Long>> userIsPaidTrackResult = userInfoFeignClient.userIsPaidTrack(albumId, trackIdList);
				Map<Long, Long> map = userIsPaidTrackResult.getData();

				records.stream().filter(track -> track.getOrderNum() > tracksForFree).forEach(track -> {
					Long trackId = track.getTrackId();
					Long isPaid = map.get(trackId);
					boolean isShowPaidMark =  isPaid.intValue() == 1 ? false : true ;
					track.setIsShowPaidMark(isShowPaidMark);
				});

			}

		}

		return page;
	}

	@Override
	public void updateStat(TrackStatMqVo trackStatMqVo) {

		String statType = trackStatMqVo.getStatType();
		if (SystemConstant.TRACK_STAT_PLAY.equals(statType)){
			// 更新声音播放量记录
			LambdaQueryWrapper<TrackStat> trackStatLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
			trackStatLambdaQueryWrapper.eq(TrackStat::getTrackId , trackStatMqVo.getTrackId()) ;
			trackStatLambdaQueryWrapper.eq(TrackStat::getStatType , statType) ;
			TrackStat trackStat = trackStatMapper.selectOne(trackStatLambdaQueryWrapper);
			trackStat.setStatNum(trackStat.getStatNum() + trackStatMqVo.getCount());
			trackStatMapper.updateById(trackStat) ;


			LambdaQueryWrapper<AlbumStat> albumStatLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
			albumStatLambdaQueryWrapper.eq(AlbumStat::getAlbumId , trackStatMqVo.getAlbumId()) ;
			albumStatLambdaQueryWrapper.eq(AlbumStat::getStatType , SystemConstant.ALBUM_STAT_PLAY) ;
			AlbumStat albumStat = albumStatMapper.selectOne(albumStatLambdaQueryWrapper);
			albumStat.setStatNum(albumStat.getStatNum() + trackStatMqVo.getCount());
			albumStatMapper.updateById(albumStat) ;
		}
	}

	@Override
	public TrackStatVo getTrackStatVo(Long trackId) {
		TrackStatVo trackStatVo = trackStatMapper.getTrackStatVo(trackId);
		return trackStatVo;
	}

	@Override
	public List<TrackPayVo> findUserTrackPaidList(Long trackId) {

		// 查询用户所点击的声音下面所有的声音列表
		// 1.1 先根据声音的id查询声音信息
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

		// 根据专辑的id查询专辑数据
		Long albumId = trackInfo.getAlbumId();
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);

		// 1.2 根据专辑id和用户所点击的声音的orderNum进行条件查询
		LambdaQueryWrapper<TrackInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		lambdaQueryWrapper.eq(TrackInfo::getAlbumId , trackInfo.getAlbumId()) ;
		lambdaQueryWrapper.gt(TrackInfo::getOrderNum , trackInfo.getOrderNum()) ;
		List<TrackInfo> trackInfoList = trackInfoMapper.selectList(lambdaQueryWrapper);

		// 查询当前登录用户购买过的声音集合
		Result<List<Long>> userPaidTrackList = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
		List<Long> trackListData = userPaidTrackList.getData();   // 存储的是用户购买过的声音的id


		// 创建一个List集合，存储用户构建声音分集列表的声音id
		List<Long> trackIdNoReaptList = new ArrayList<>() ;
		if(CollectionUtils.isEmpty(trackListData)) {
			trackIdNoReaptList = trackInfoList.stream().map(track -> track.getId()).collect(Collectors.toList());
		}else {		// 存在购买过的声音的id，那么此时就需要从trackInfoList集合中，排除购买过的声音的id，得到未购买过的声音的id集合
			trackIdNoReaptList = trackInfoList.stream().map(track -> track.getId()).filter(stremTrackId -> !trackListData.contains(stremTrackId))
					.collect(Collectors.toList());
		}

		// 创建一个List集合，存储声音的购买分集列表数据
		List<TrackPayVo> trackPayVoList = new ArrayList<>();

		// 构建本集这条数据
		TrackPayVo trackPayVo = new TrackPayVo() ;
		trackPayVo.setName("本集");
		trackPayVo.setPrice(albumInfo.getPrice());
		trackPayVo.setTrackCount(0);
		trackPayVoList.add(trackPayVo) ;

		// 每10集构建一个分集数据
		int size = trackIdNoReaptList.size();
		if(size > 0 && size <= 10) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 10) {		// 构建后10集
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后10集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(10)));
			trackVo.setTrackCount(10);
			trackPayVoList.add(trackVo);
		}

		if(size > 10 && size <= 20) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 20) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后20集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(20)));
			trackVo.setTrackCount(20);
			trackPayVoList.add(trackVo);
		}

		if(size > 20 && size <= 30) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 30) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后30集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(30)));
			trackVo.setTrackCount(30);
			trackPayVoList.add(trackVo);
		}

		if(size > 30 && size <= 40) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 40) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后40集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(40)));
			trackVo.setTrackCount(40);
			trackPayVoList.add(trackVo);
		}

		if(size > 40 && size <= 50) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 50) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后50集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(50)));
			trackVo.setTrackCount(50);
			trackPayVoList.add(trackVo);
		}

		// 返回
		return trackPayVoList;

	}

	@Override
	public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer num) {
		//创建一个List集合存储要购买的声音的数据
		List<TrackInfo> trackInfoList = new ArrayList<>() ;

		// 根据当前的声音的id查询声音信息
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

		// 查询当前登录用户所购买过的声音id集合
		Long albumId = trackInfo.getAlbumId();
		Result<List<Long>> userPaidTrackListResult = userInfoFeignClient.findUserPaidTrackList(albumId);
		List<Long> userPaidTrackIds = userPaidTrackListResult.getData();		// 用户购买过的声音的id的集合

		// 判断num是否是大于0 ， 如果是大于0返回的list集合中就会包含多个声音数据
		if(num > 0) {

			// select * from track_info where album_id = ? and order_num > ? id not in (? , ?)  order by order_num asc limit ?
			LambdaQueryWrapper<TrackInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
			lambdaQueryWrapper.eq(TrackInfo::getAlbumId , albumId) ;
			lambdaQueryWrapper.gt(TrackInfo::getOrderNum , trackInfo.getOrderNum()) ;
			if(!CollectionUtils.isEmpty(userPaidTrackIds)) {
				lambdaQueryWrapper.notIn( TrackInfo::getId , userPaidTrackIds) ;
			}
			lambdaQueryWrapper.orderByAsc(TrackInfo::getOrderNum) ;
			lambdaQueryWrapper.last("limit " + num) ;
			trackInfoList = trackInfoMapper.selectList(lambdaQueryWrapper);

		}else {
			trackInfoList.add(trackInfo) ;
		}

		return trackInfoList;
	}

}